// 2010-02-25 - M. Caputo

#include "GlWidget.h"
#include "WireframeMode.h"
#include "DotMode.h"
#include "FlatShadedMode.h"

GlWidget::GlWidget(QWidget *parent): QGLWidget(parent)
{
	scene = 0;
	
	renderModes.append(new WireframeMode());
	renderModes.append(new DotMode());
	renderModes.append(new FlatShadedMode());
	activeMode = 0;
	
	resetView();
}

GlWidget::~GlWidget()
{
	for(int i=0; i<renderModes.size(); i++) {
		delete renderModes[i];
	}
}

void GlWidget::initializeGL()
{
	glClearColor(
		backgroundColor.redF(),
		backgroundColor.greenF(),
		backgroundColor.blueF(),
		backgroundColor.alphaF()
	);

	renderModes[activeMode]->setSettings();
}

void GlWidget::resizeGL(int w, int h)
{
	int side = qMin(w, h);
    glViewport((w - side) / 2, (h - side) / 2, side, side);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	glFrustum(-1.0, +1.0, -1.0, +1.0, 1.5, 20.0);
	glMatrixMode(GL_MODELVIEW);
}

void GlWidget::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	
	glTranslatef(0.0, 0.0, -3.0);
	
	glScalef(scale, scale, scale);
	
	glTranslatef(xTrans, yTrans, zTrans);
	
	glRotatef(xRot/2.0, 1.0, 0.0, 0.0);
	glRotatef(yRot/2.0, 0.0, 1.0, 0.0);
	glRotatef(zRot/2.0, 0.0, 0.0, 1.0);
	
	if (axes) drawAxes();
	if (planes[0]) drawXzPlane();
	if (planes[1]) drawXyPlane();
	if (planes[2]) drawYzPlane();
	
	if (scene) {
		renderModes[activeMode]->draw(scene, objectColor);
	}
}

void GlWidget::mousePressEvent(QMouseEvent *event)
{
	lastPos = event->pos();
}

void GlWidget::mouseMoveEvent(QMouseEvent *event)
{
	int dx = event->x() - lastPos.x();
	int dy = event->y() - lastPos.y();

	if (event->buttons() & Qt::LeftButton) {
		xRot += dy;
		yRot += dx;
	} else if (event->buttons() & Qt::RightButton) {
		xRot += dy;
		zRot += dx;
	}
	
	lastPos = event->pos();
	updateGL();
}

void GlWidget::wheelEvent(QWheelEvent *event)
{
	if (event->delta() > 0) {
		scale += 0.1;
	} else {
		if (scale > 0.1) scale -= 0.1;
	}

	updateGL();
}

void GlWidget::drawAxes()
{
	glLineWidth (3.0);
	glBegin( GL_LINES );	
		glColor3f(1, 0, 0);
		glVertex3f(0,0,0);
		glVertex3f(1,0,0);
		
		glColor3f(0, 1, 0);
		glVertex3f(0,0,0);
		glVertex3f(0,1,0);

		glColor3f(0, 0, 1);
		glVertex3f(0,0,0);
		glVertex3f(0,0,1);	
	glEnd();
	glLineWidth (1.0);
}

void GlWidget::drawXzPlane()
{
	glColor3f(0.4, 0.4, 0.4);
	glBegin( GL_LINES );
	for(int i=-10; i<=10; i++) {
		glVertex3f(0.1*i,0,-1);
		glVertex3f(0.1*i,0,1);
	}
	for(int i=-10; i<=10; i++) {
		glVertex3f(-1,0,0.1*i);
		glVertex3f(1,0,0.1*i);
	}	
	glEnd();
}

void GlWidget::drawXyPlane()
{
	
}

void GlWidget::drawYzPlane()
{
	
}

void GlWidget::setScene(IScene *scene)
{
	this->scene = scene;
	updateGL();
}

void GlWidget::setBackgroundColor(const QColor & color)
{
	backgroundColor = color;
}

void GlWidget::setObjectColor(const QColor & color)
{
	objectColor = color;
}

void GlWidget::setPlanes(bool xz, bool xy, bool yz)
{
	planes[0] = xz;
	planes[1] = xy;
	planes[2] = yz;
}

void GlWidget::setAxes(bool showAxes)
{
	this->axes = showAxes;
}

void GlWidget::resetView()
{
	objectColor = QColor("white");
	backgroundColor = QColor("black");
	
	axes = true;
	
	planes[0] = true;
	planes[1] = false;
	planes[2] = false;

	scale = 1.0;
	
	xRot = 0;
	yRot = 0;
	zRot = 0;
	
	xTrans = 0;
	yTrans = 0;
	zTrans = 0;
}

QVector<QString> GlWidget::listRenderModes()
{
	QVector<QString> list;
	for(int i=0; i<renderModes.size(); i++) {
		list.append(renderModes[i]->name());
	}
	return list;
}

int GlWidget::renderMode()
{
	return activeMode;
}

void GlWidget::setRenderMode(int m)
{
	renderModes[activeMode]->unsetSettings();
	activeMode = m;
	renderModes[activeMode]->setSettings();
}
